import { ethers } from 'ethers';
import { all } from './call';
import { getEthBalance } from './calls';
import { ContractCall } from './types';

export class Provider {
  private _provider: ethers.providers.Provider;
  private _multicallAddress: string;

  constructor(provider: ethers.providers.Provider, chainId?: number) {
    this._provider = provider;
    this._multicallAddress = getAddressForChainId(chainId);
  }

  public async init() {
    // Only required if `chainId` was not provided in constructor
    this._multicallAddress = await getAddress(this._provider);
  }

  public getEthBalance(address: string) {
    if (!this._provider) {
      throw new Error('Provider should be initialized before use.');
    }
    return getEthBalance(address, this._multicallAddress);
  }

  public async all<T extends any[] = any[]>(calls: ContractCall[]) {
    if (!this._provider) {
      throw new Error('Provider should be initialized before use.');
    }
    return all<T>(calls, this._multicallAddress, this._provider);
  }
}

const multicallAddresses = {
  1: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
  3: '0xF24b01476a55d635118ca848fbc7Dab69d403be3',
  4: '0x42ad527de7d4e9d9d011ac45b31d8551f8fe9821',
  5: '0x77dca2c955b15e9de4dbbcf1246b4b85b651e50e',
  42: '0x2cc8688c5f75e365aaeeb4ea8d6a480405a48d2a',
  100: '0xb5b692a88bdfc81ca69dcb1d924f59f0413a602a',
  137: '0xc4f1501f337079077842343Ce02665D8960150B0',
  1337: '0x77dca2c955b15e9de4dbbcf1246b4b85b651e50e',
  80001: '0x5a0439824F4c0275faa88F2a7C5037F9833E29f1',
  8285: '0xa6Ea066Bae96432414ac62818e62E2ECAa570dE3',
  256: '0x9b0F3F29eC68e7312cEE9818B2Ab2113bcC07911',
  97: '0x19d8860A7313e3484ef9418E49E8d76B4E699962',
  56: '0x3e6618bE74EeE2a0C492485490C7221F6Bb33c68',
  2559:'0xE201bB4955C767765C8F996398d6a7e0c699B9Ff',
};

export function setMulticallAddress(chainId: number, address: string) {
  multicallAddresses[chainId] = address;
}

function getAddressForChainId(chainId: number) {
  return multicallAddresses[chainId];
}

async function getAddress(provider: ethers.providers.Provider) {
  const { chainId } = await provider.getNetwork();
  return getAddressForChainId(chainId);
}
